package emu.decvices.bus;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * CPU的IRQ线
 *
 * IRQ (interrupt request) is a signal on the NES CPU. It is used to trigger a CPU interrupt.
 *
 * If the CPU's /IRQ input is 0 at the end of an instruction, then the CPU pushes the program counter and the processor status register, sets the I flag to ignore further IRQs, and the Program Counter takes the value read at $fffe and $ffff.
 *
 * This behaviour is masked by the CPU's interrupt-disable status flag. The SEI instruction disables IRQs, and the CLI instruction enables them.
 *
 * /IRQ functions as an open collector input: it is normally 1, but any device on the CPU bus can pull it down to 0. An IRQ handler is expected to push any registers it uses, acknowledge the interrupt by writing to a port so that the source no longer forces /IRQ to 0, pull the registers back, and return with RTI.
 *
 * Therefore if a program uses more than one source of IRQ, the priority between the conflicting interrupts should be handled in software.
 *
 * Sources of IRQ on a Famicom or NES include
 *
 * IRQ（中断请求）是 NES CPU 上的一个信号。它用于触发 CPU 中断。
 * 如果 CPU 的 /IRQ 输入在指令结束时为 0，则 CPU 会推送程序计数器和处理器状态寄存器，
 * 设置 I 标志以忽略其他 IRQ，并且程序计数器会读取 $fffe 和 $ffff 的值。
 *
 * CPU 的中断禁用状态标志掩盖了这种行为。SEI 指令禁用 IRQ，CLI 指令启用 IRQ。
 *
 * /IRQ 处理程序应推送其使用的任何寄存器，通过写入端口确认中断，使中断源不再将 /IRQ 强制为 0，然后拉回寄存器，并返回 RTI。
 *
 * 因此，如果程序使用多个 IRQ 源，则应通过软件处理相互冲突的中断之间的优先级。
 *
 * Famicom 或 NES 上的 IRQ 源包括
 *
 *
 */
public class IRQLine implements Serializable {
    private static IRQLine instance = new IRQLine();
    private List<IRQLineDevice> devices = new ArrayList<>();

    public boolean needIrq(){
        for(IRQLineDevice device : devices){
            if(device.needIRQ()){
                return true;
            }
        }
        return false;
    }

    /**
     * 向中断线添加设备
     * @param device
     */
    public void addDevice(IRQLineDevice device){
        devices.add(device);
    }

    public void reset(){
        devices.clear();
    }

    public static IRQLine getInstance(){
        return instance;
    }

    public static void setInstance(IRQLine i){
        instance = i;
    }
}
